﻿using System;
using System.Linq;
using System.Linq.Expressions;
using LinqToLdap;
using LinqToLdap.Mapping;

namespace ActiveDirectoryService.Library.ExtensionMethods
{
    public static class LdapExtensionMethods
    {
        public static TK GetPropertyValue<T, TK>(this T obj, string propertyName)
        {
            var prop = obj.GetType().GetProperty(propertyName);
            if (prop == null) return default(TK);
            return (TK)prop.GetValue(obj, null);
        }

        public static string GetActiveDirectoryPropertyName<T>(this T obj, string name)
        {
            var prop = obj.GetType().GetProperty(name);
            if (prop != null)
            {
                var attr = prop.GetCustomAttributes(typeof(DirectoryAttributeAttribute), true).SingleOrDefault() as DirectoryAttributeAttribute;
                if (attr != null)
                {
                    return attr.AttributeName;
                }
                throw new Exception(String.Format("DirectoryAttribute  was not defined for property '{0}'", name));
            }
            throw new Exception(String.Format("Property '{0}' was not found", name));
        }

        public static Expression<Func<T, bool>> FilterAttributeList<T>(this T obj, string propertyName, char separator)
        {
            return u => Filter.EqualAny(u, obj.GetActiveDirectoryPropertyName(propertyName), obj.GetPropertyValue<T, string>(propertyName).Split(separator));
        }

        public static Expression<Func<T, bool>> FilterAttribute<T>(this T obj, string propertyName)
        {
            return u => Filter.Equal(u, obj.GetActiveDirectoryPropertyName(propertyName), obj.GetPropertyValue<T, string>(propertyName));
        }

        public static Expression<Func<T, bool>> BuildExpressionTree<T>(this T obj, char separator = '+') where T : DirectoryObjectBase
        {
            var predicate = PredicateBuilder.Create<T>();

            var properties = obj.GetType().GetProperties().Where(p => p.PropertyType.Name == typeof(string).Name).ToList();

            if (properties.Count > 0)
            {
                properties.ForEach(prop =>
                {
                    var val = prop.GetValue(obj, null) as string;

                    if (!String.IsNullOrEmpty(val))
                    {
                        predicate = (val.Contains(separator)
                                        ? predicate.And(obj.FilterAttributeList(prop.Name, separator))
                                        : predicate.And(obj.FilterAttribute(prop.Name)));
                    }
                });
            }
            return predicate;
        }
    }
}